package xj.graph2d;

import static xj.graph2d.DrawShapeConstants.SCALE_EXCLUDE_GUTTER;

import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;

public class RectangleShape 
  extends TwoEndsNodeShape 
  implements Rotatable {

  public RectangleShape() {
    this(false, false);
  }

  public RectangleShape(boolean filled) {
    this(filled, false);
  }

  public RectangleShape(boolean filled, boolean createComp) {
    super(createComp);
    needFrameRect = false;
    this.filled = filled;
  }

  public RectangleShape(float x1, float y1, float x2, float y2) {
    this(x1, y1, x2, y2, false, false);
  }

  public RectangleShape(float x1, float y1, float x2, float y2, boolean filled) {
    this(x1, y1, x2, y2, filled, false);
  }

  public RectangleShape(float x1, float y1, float x2, float y2, 
			boolean filled, boolean createComp) {
    super(createComp);
    this.filled = filled;
    needFrameRect = false;
    setEnds(x1, y1, x2, y2);
  }

  public DrawShape makeInstance() {
    return new RectangleShape(filled, fullCloneMode && comp != null);
  }

  @Override
  public void copyTo(DrawShapeBase s) 
    throws CloneNotSupportedException {
    if (s != null) {
      super.copyTo(s);
      if (s instanceof RectangleShape) {
	RectangleShape r = (RectangleShape) s;
	r.threeD = threeD;
	r.raised = raised;
	r.fixedWidth = fixedWidth;
	r.fixedHeight = fixedHeight;
	r.showVerticalGutter = showVerticalGutter;
	r.gutterWidth = gutterWidth;
      }
    }
  }

  @Override
  public String getName() {
    return "Rectangle";
  }

  public boolean isFixedWidth() {
    return fixedWidth;
  }

  public void setFixedWidth(boolean b) {
    fixedWidth = b;
  }

  public boolean isFixedHeight() {
    return fixedHeight;
  }

  public void setFixedHeight(boolean b) {
    fixedHeight = b;
  }

  public boolean isThreeD() {
    return threeD;
  }

  public boolean isRaised() {
    return raised;
  }

  public void setThreeD(boolean threeD, boolean raised) {
    this.threeD = threeD;
    this.raised = raised;
  }

  public boolean isShowVerticalGutter() {
    return showVerticalGutter;
  }

  public void setShowVerticalGutter(boolean showVerticalGutter) {
    this.showVerticalGutter = showVerticalGutter;
  }

  public int getGutterWidth() {
    return gutterWidth;
  }

  public void setGutterWidth(int gutterWidth) {
    this.gutterWidth = gutterWidth;
  }

  @Override
  protected void scaleEx(float sx, float sy) {
    if ((scaleMode & SCALE_EXCLUDE_GUTTER) == 0) {
      gutterWidth *= sx;
    }
  }

  @Override
  public void draw(Graphics2D g2) {
    float x = (float) Math.min(p1.getX(), p2.getX());
    float y = (float) Math.min(p1.getY(), p2.getY());
    float w = (float) Math.abs(p1.getX() - p2.getX());
    float h = (float) Math.abs(p1.getY() - p2.getY());

    if (threeD) {
      if (filled) {
	g2.fill3DRect((int) x, (int) y, (int) w, (int) h, raised);
      } else {
	g2.draw3DRect((int) x, (int) y, (int) w, (int) h, raised);
      }
    } else {
      Shape shape = new Rectangle2D.Float(x, y, w, h);
      if (filled) {
	fillBackground(g2, x, y, w, h, shape);
	if (showborder) {
	  g2.draw(shape);
	}
      } else {
	if (showborder) {
	  g2.draw(shape);
	}
      }
    }

    drawGutter(g2, x, y, w, h);
  }

  protected void drawGutter(Graphics2D g2, float x, float y, float w, float h) {
    if (showVerticalGutter && w > gutterWidth * 2) {
      g2.draw(new Line2D.Float(x + gutterWidth, y, x + gutterWidth, y + h));
      g2.draw(new Line2D.Float(x + w - gutterWidth, y, x + w - gutterWidth, y + h));
    }
  }

  @Override
  public void drawOutline(Graphics2D g2, float x1, float y1, float x2, float y2) {
    DrawAttr attr = getDrawAttr();
    if (attr != null) {
      g2.setColor(attr.getPenColor());
    } else {
      g2.setColor(DrawAttr.getDefaultPenColor());
    }
    float x = Math.min(x1, x2);
    float y = Math.min(y1, y2);
    float w = Math.abs(x1 - x2);
    float h = Math.abs(y1 - y2);
    g2.draw(new Rectangle2D.Float(x, y, w, h));
    if (showVerticalGutter && w > gutterWidth * 2) {
      g2.draw(new Line2D.Float(x + gutterWidth, y, x + gutterWidth, y + h));
      g2.draw(new Line2D.Float(x + w - gutterWidth, y, 
			       x + w - gutterWidth, y + h));
    }
    drawSubShapesOutline(g2);
  }

  @Override
  public void moveCorner(int pos, float dx, float dy, boolean scaleSubshapes) {
    if (fixedWidth) {
      dx = 0;
    }
    if (fixedHeight) {
      dy = 0;
    }
    super.moveCorner(pos, dx, dy, scaleSubshapes);
  }

  @Override
  public void moveEdge(int pos, float dx, float dy, boolean scaleSubshapes) {
    if (fixedWidth) {
      dx = 0;
    }
    if (fixedHeight) {
      dy = 0;
    }
    super.moveEdge(pos, dx, dy, scaleSubshapes);
  }

  @Override
  protected Map<String, Object> getXMLAttributes() {
    Map<String, Object> attrs = super.getXMLAttributes();
    if (attrs == null) {
      attrs = new HashMap<String, Object>();
    }
    attrs.put("fixedWidth", fixedWidth);
    attrs.put("fixedHeight", fixedHeight);
    attrs.put("showVerticalGutter", showVerticalGutter);
    attrs.put("gutterWidth", gutterWidth);
    return attrs;
  }

  @Override
  protected void processXMLAttributes(org.w3c.dom.Element node) {
    if (node != null) {
      super.processXMLAttributes(node);

      String s;
      s = node.getAttribute("fixedWidth");
      fixedWidth = Boolean.valueOf(s);
      s = node.getAttribute("fixedHeight");
      fixedHeight = Boolean.valueOf(s);
      s = node.getAttribute("shadowWidth");
      try {
	shadowWidth = Integer.parseInt(s);
      } catch (NumberFormatException ex) {
      }

      s = node.getAttribute("showVerticalGutter");
      showVerticalGutter = Boolean.valueOf(s);
      s = node.getAttribute("sgutterWidth");
      try {
	gutterWidth = Integer.parseInt(s);
      } catch (NumberFormatException ex) {
      }
    }
  }

  protected boolean threeD = false;

  protected boolean raised = false;

  protected boolean fixedWidth = false, fixedHeight = false;

  protected boolean showVerticalGutter = false;

  protected int gutterWidth = 10;

}
